package com.yeskery.nut.util;

import com.yeskery.nut.core.NutException;

import java.io.*;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Pem 格式的证书的工具类
 * @author sprout
 * 2019-03-21 16:04
 * @version 1.0
 */
public class PemUtils {

	/** 日志对象 */
	private static final Logger logger = Logger.getLogger(PemUtils.class.getName());

	/**
	 * 私有化构造方法
	 */
	private PemUtils() {
	}

	/**
	 * 读取公钥
	 * @param key 公钥的路径
	 * @return 公钥
	 */
	public static PublicKey readPublicKey(String key) {
		return (PublicKey) generateKey(key, true);
	}

	/**
	 * 读取私钥
	 * @param key 私钥的路径
	 * @return 私钥
	 */
	public static PrivateKey readPrivateKey(String key) {
		return (PrivateKey) generateKey(key, false);
	}

	/**
	 * 从秘钥路径读取证书信息，返回格式为 {@link X509Certificate}
	 * @param key 秘钥路径
	 * @return 证书信息
	 */
	public static X509Certificate readCertificate(String key) {
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(key);
			CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
			return (X509Certificate) certificateFactory.generateCertificate(inputStream);
		} catch (CertificateException | FileNotFoundException e) {
			throw new NutException(e);
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					logger.log(Level.WARNING, "An error occurred while closing the stream.", e);
				}
			}
		}
	}

	/** 从秘钥路径读取证书信息 */
	private static Object generateKey(String key, boolean publicKey) {
		BufferedReader bufferedReader = null;
		FileReader fileReader = null;
		try {
			Base64.Decoder base64decoder = Base64.getDecoder();
			//读取pem证书
			fileReader = new FileReader(key);
			bufferedReader = new BufferedReader(fileReader);
			StringBuilder publicKeyBuilder = new StringBuilder();
			String s;
			int index = 0;
			while ((s = bufferedReader.readLine()) != null && index <= 1) {
				if (s.startsWith("-")) {
					index++;
					continue;
				}
				publicKeyBuilder.append(s);
			}
			byte[] keyBytes = base64decoder.decode(publicKeyBuilder.toString());
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			KeySpec keySpec;
			if (publicKey) {
				keySpec = new X509EncodedKeySpec(keyBytes);
			} else {
				keySpec = new PKCS8EncodedKeySpec(keyBytes);
			}
			return publicKey ? keyFactory.generatePublic(keySpec) : keyFactory.generatePrivate(keySpec);
		} catch (IOException | NoSuchAlgorithmException |InvalidKeySpecException e) {
			throw new NutException(e);
		} finally {
			try {
				if (fileReader != null) {
					fileReader.close();
				}
				if (bufferedReader != null) {
					fileReader.close();
				}
			} catch (IOException e) {
				logger.log(Level.WARNING, "An error occurred while closing the stream.", e);
			}
		}
	}
}
